package com.gagakuai.engine.impl.persistence.entity;

import com.gagakuai.engine.ProcessEngineConfiguration;
import com.gagakuai.engine.exception.PvmException;
import com.gagakuai.engine.impl.context.Context;
import com.gagakuai.engine.impl.db.PersistentObject;
import com.gagakuai.engine.impl.delegate.ActivityExecution;
import com.gagakuai.engine.impl.pvm.*;
import com.gagakuai.engine.impl.pvm.process.ActivityImpl;
import com.gagakuai.engine.impl.pvm.process.ProcessDefinitionImpl;
import com.gagakuai.engine.impl.pvm.process.TransitionImpl;
import com.gagakuai.engine.impl.pvm.runtime.AtomicOperation;
import com.gagakuai.engine.impl.pvm.runtime.StartingExecution;
import com.gagakuai.engine.impl.runtime.InterpretableExecution;
import com.gagakuai.engine.runtime.Execution;
import com.gagakuai.engine.runtime.ProcessInstance;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;




/*
*
*  在数据库中对应的映射
*
*/
public class ExecutionEntity implements ActivityExecution, InterpretableExecution, Execution, PersistentObject, ProcessInstance {


    protected String tenantId = ProcessEngineConfiguration.NO_TENANT_ID;
    /*
     * 表示范围或并发路径的嵌套执行
     */
    protected List<ExecutionEntity> executions;
    /*
     * 注入到流程虚拟机的流程定义
     */
    protected ProcessDefinitionImpl processDefinition;
    /*
     * 当前活动
     */
    protected ActivityImpl activity;
    /*
     *
     */
    protected TransitionImpl transition = null;


    protected StartingExecution startingExecution;

    /*
     * 流程实例。这是执行树的根。
     * 一个流程实例的processInstance是一个自引用
     * ProcessInstacne
     *      |
     * /  /  / /
     * Execution Execution Execution
     */
    protected ExecutionEntity processInstance;

    /*
     * 持久引用此执行的父项。
     */
    protected String parentId;

    public void setExecutions(List<ExecutionEntity> executions) {
        this.executions = executions;
    }

    @Override
    public void signal(String signalName, Object signalData) {

    }

    @Override
    public PvmActivity getActivity() {
        return null;
    }

    @Override
    public boolean hasVariable(String variableName) {
        return false;
    }

    @Override
    public void setVariable(String variableName, Object value) {

    }

    @Override
    public Object getVariable(String variableName) {
        return null;
    }

    @Override
    public Map<String, Object> getVariables() {
        return null;
    }

    @Override
    public boolean isProcessInstanceType() {
        return parentId == null;
    }

    @Override
    public ExecutionEntity createExecution() {

        ExecutionEntity executionEntity = newExecution();
        ensureExecutionsInitialized();
        executions.add(executionEntity);
        /*
         *  // TODO: 2023/1/2   后面业务逻辑再处理
         */


        return executionEntity;
    }

    protected ExecutionEntity newExecution() {
        ExecutionEntity newExecution = new ExecutionEntity();
        newExecution.executions = new ArrayList<>();

        if (getTenantId() != null) {
            newExecution.setTenantId(getTenantId());
        }

        //// TODO: 2023/1/2 做持久化操作
        Context.getCommandContext()
                .getDbSqlSession()
                .insert(newExecution);
        return newExecution;
    }

    protected void ensureExecutionsInitialized() {
      /*  if (executions==null) {
            this.executions = (List) Context
                    .getCommandContext()
                    .getExecutionEntityManager()
                    .findChildExecutionsByParentExecutionId(id);
        }*/
    }

    @Override
    public void take(PvmTransition transition) {
        take(transition, true);
    }

    public void take(PvmTransition transition, boolean fireActivityCompletionEvent) {
        // 转发ACTIVITY_COMPLETED 事件
        if (fireActivityCompletionEvent) {
            //todo
            fireActivityCompletedEvent();
        }

        if (this.transition!=null) {
            throw new PvmException("already taking a transition");
        }
        if (transition==null) {
            throw new PvmException("transition is null");
        }
        //
        setActivity((ActivityImpl)transition.getSource());
        setTransition((TransitionImpl) transition);
        //执行
        performOperation(AtomicOperation.TRANSITION_NOTIFY_LISTENER_END);
    }

    @Override
    public PvmProcessInstance createSubProcessInstance(PvmProcessDefinition processDefinition) {
        return null;
    }

    @Override
    public ActivityExecution getParent() {
        return null;
    }

    @Override
    public List<? extends ActivityExecution> getExecutions() {
        return null;
    }

    @Override
    public void end() {

    }

    @Override
    public String getId() {
        return null;
    }

    @Override
    public void setId(String id) {

    }

    @Override
    public Object getPersistentState() {
        return null;
    }

    @Override
    public boolean isSuspected() {
        return false;
    }

    @Override
    public void start() {

        if (startingExecution == null && isProcessInstanceType()) {
            startingExecution = new StartingExecution(processDefinition.getInitial());
        }
        /*
         *  调度:表示流程开始
         */
        performOperation(AtomicOperation.PROCESS_START);


    }

    @Override
    public PvmExecution findExecution(String activityId) {
        return null;
    }

    @Override
    public List<String> findActivityIds() {
        return null;
    }

    @Override
    public boolean isEnded() {
        return false;
    }

    @Override
    public void deleteCascade(String deleteReason) {

    }

    @Override
    public void setBusinessKey(String businessKey) {

    }

    @Override
    public String getActivityId() {
        return null;
    }

    @Override
    public String getProcessInstanceId() {
        return null;
    }

    @Override
    public String getSuperExecutionId() {
        return null;
    }

    @Override
    public String getTenantId() {
        return this.tenantId;
    }

    public void setTenantId(String tenantId) {
        this.tenantId = tenantId;
    }

    @Override
    public String getName() {
        return null;
    }

    @Override
    public String getDescription() {
        return null;
    }

    @Override
    public String getLocalizedName() {
        return null;
    }

    @Override
    public String getLocalizedDescription() {
        return null;
    }

    @Override
    public String petProcessInstanceId() {
        return null;
    }

    @Override
    public String getBusinessKey() {
        return null;
    }

    @Override
    public boolean isSuspended() {
        return false;
    }

    @Override
    public Map<String, Object> getProcessVariables() {
        return null;
    }

    @Override
    public String getProcessBusinessKey() {
        return null;
    }

    @Override
    public String getProcessDefinitionId() {
        return null;
    }

    @Override
    public String getProcessDefinitionName() {
        return null;
    }

    @Override
    public String getProcessDefinitionKey() {
        return null;
    }

    @Override
    public Integer getProcessDefinitionVersion() {
        return null;
    }

    @Override
    public String getDeploymentId() {
        return null;
    }

    @Override
    public String getCurrentActivityId() {
        return null;
    }

    @Override
    public String getCurrentActivityName() {
        return null;
    }

    @Override
    public void setActivity(ActivityImpl activity) {


    }

    @Override
    public ExecutionEntity getProcessInstance() {
        // ensureProcessInstanceInitialized(); // TODO: 2023/1/2  
        return processInstance;
    }

    @Override
    public void performOperation(AtomicOperation executionOperation) {

        //判断是否异步执行
        if (executionOperation.isAsync(this)) {
            scheduleAtomicOperationAsync(executionOperation);
        } else {
            performOperationSync(executionOperation);
        }

    }

    protected void performOperationSync(AtomicOperation executionOperation) {

        Context.getCommandContext()
                .performOperation(executionOperation,this);
    }

    protected void scheduleAtomicOperationAsync(AtomicOperation executionOperation) {
    }


    @Override
    public ProcessDefinitionImpl getProcessDefinition() {
       
        return null;
    }

    @Override
    public StartingExecution getStartingExecution() {
        return null;
    }

    @Override
    public InterpretableExecution getReplacedBy() {
        return null;
    }
}